1use crate::ext::io::*;
2use anyhow::Result;
3use int_enum::IntEnum;
4use std::collections::HashMap;
5use std::io::{Read, Write};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8enum Oper {
9 P,
10 I,
11 L,
12}
13
14use Oper::*;
15
16const OPS: [(u16, (Option<&'static str>, &'static [Oper])); 210] = [
17 (0x0001, (Some("mov"), &[P, P])),
18 (0x0002, (Some("add"), &[P, P])),
19 (0x0003, (Some("sub"), &[P, P])),
20 (0x0004, (Some("mul"), &[P, P])),
21 (0x0005, (Some("div"), &[P, P])),
22 (0x0006, (Some("binand"), &[P, P])),
23 (0x0007, (Some("binor"), &[P, P])),
24 (0x0008, (Some("binxor"), &[P, P])),
25 (0x0009, (Some("jmp"), &[L])),
26 (0x000A, (Some("jz"), &[L, P])),
27 (0x000B, (Some("call"), &[L])),
28 (0x000C, (Some("eq"), &[P, P])),
29 (0x000D, (Some("neq"), &[P, P])),
30 (0x000E, (Some("le"), &[P, P])),
31 (0x000F, (Some("ge"), &[P, P])),
32 (0x0010, (Some("lt"), &[P, P])),
33 (0x0011, (Some("gt"), &[P, P])),
34 (0x0012, (Some("logor"), &[P, P])),
35 (0x0013, (Some("logand"), &[P, P])),
36 (0x0014, (Some("not"), &[I])),
37 (0x0015, (Some("exit"), &[])),
38 (0x0016, (Some("nop"), &[])),
39 (0x0017, (Some("syscall"), &[I, I])),
40 (0x0018, (Some("ret"), &[])),
41 (0x0019, (None, &[])),
42 (0x001A, (Some("mod"), &[P, P])),
43 (0x001B, (Some("shl"), &[P, P])),
44 (0x001C, (Some("sar"), &[P, P])),
45 (0x001D, (Some("neg"), &[I])),
46 (0x001E, (Some("pop"), &[P])),
47 (0x001F, (Some("push"), &[P])),
48 (0x0020, (Some("enter"), &[P])),
49 (0x0021, (Some("leave"), &[P])),
50 (0x0023, (Some("create_message"), &[])),
51 (0x0024, (Some("get_message"), &[])),
52 (0x0025, (Some("get_message_param"), &[])),
53 (0x0028, (Some("se_load"), &[])),
54 (0x0029, (Some("se_play"), &[])),
55 (0x002A, (Some("se_play_ex"), &[])),
56 (0x002B, (Some("se_stop"), &[])),
57 (0x002C, (Some("se_set_volume"), &[])),
58 (0x002D, (Some("se_get_volume"), &[])),
59 (0x002E, (Some("se_unload"), &[])),
60 (0x002F, (Some("se_wait"), &[])),
61 (0x0030, (Some("set_se_info"), &[])),
62 (0x0031, (Some("get_se_ex_volume"), &[])),
63 (0x0032, (Some("set_se_ex_volume"), &[])),
64 (0x0033, (Some("se_enable"), &[])),
65 (0x0034, (Some("is_se_enable"), &[])),
66 (0x0035, (Some("se_set_pan"), &[])),
67 (0x0036, (Some("se_mute"), &[])),
68 (0x0038, (Some("select_init"), &[])),
69 (0x0039, (Some("select"), &[])),
70 (0x003A, (Some("select_add_choice"), &[])),
71 (0x003B, (Some("end_select"), &[])),
72 (0x003C, (Some("select_clear"), &[])),
73 (0x003D, (Some("select_set_offset"), &[])),
74 (0x003E, (Some("select_set_process"), &[])),
75 (0x003F, (Some("select_lock"), &[])),
76 (0x0040, (Some("get_select_on_key"), &[])),
77 (0x0041, (Some("get_select_pull_key"), &[])),
78 (0x0042, (Some("get_select_push_key"), &[])),
79 (0x0044, (Some("skip_set"), &[])),
80 (0x0045, (Some("skip_is"), &[])),
81 (0x0046, (Some("auto_set"), &[])),
82 (0x0047, (Some("auto_is"), &[])),
83 (0x0048, (Some("auto_set_time"), &[])),
84 (0x0049, (Some("auto_get_time"), &[])),
85 (0x004A, (Some("window_set_mode"), &[])),
86 (0x004B, (None, &[])),
87 (0x004C, (None, &[])),
88 (0x004D, (None, &[])),
89 (0x004E, (None, &[])),
90 (0x004F, (Some("effect_enable_is"), &[])),
91 (0x0050, (Some("cursor_pos_get"), &[])),
92 (0x0051, (Some("time_get"), &[])),
93 (0x0052, (None, &[])),
94 (0x0053, (Some("load_font"), &[])),
95 (0x0054, (Some("unload_font"), &[])),
96 (0x0055, (Some("set_font_type"), &[])),
97 (0x0056, (Some("key_cancel"), &[])),
98 (0x0057, (Some("set_font_color"), &[])),
99 (0x0058, (Some("load_font_ex"), &[])),
100 (0x0059, (None, &[])),
101 (0x005A, (None, &[])),
102 (0x005B, (Some("lpush"), &[])),
103 (0x005C, (Some("lpop"), &[])),
104 (0x005D, (None, &[])),
105 (0x005E, (None, &[])),
106 (0x005F, (Some("set_font_size"), &[])),
107 (0x0060, (Some("get_font_size"), &[])),
108 (0x0061, (Some("get_font_type"), &[])),
109 (0x0062, (Some("set_font_effect"), &[])),
110 (0x0063, (Some("get_font_effect"), &[])),
111 (0x0064, (Some("get_pull_key"), &[])),
112 (0x0065, (Some("get_on_key"), &[])),
113 (0x0066, (Some("get_push_key"), &[])),
114 (0x0067, (Some("input_clear"), &[])),
115 (0x0068, (Some("change_window_size"), &[])),
116 (0x0069, (Some("change_aspect_mode"), &[])),
117 (0x006A, (Some("aspect_position_enable"), &[])),
118 (0x006B, (None, &[])),
119 (0x006C, (Some("get_aspect_mode"), &[])),
120 (0x006D, (Some("get_monitor_size"), &[])),
121 (0x006E, (Some("get_window_pos"), &[])),
122 (0x006F, (Some("get_system_metrics"), &[])),
123 (0x0070, (Some("set_system_path"), &[])),
124 (0x0071, (Some("set_allmosaicthumbnail"), &[])),
125 (0x0072, (Some("enable_window_change"), &[])),
126 (0x0073, (Some("is_enable_window_change"), &[])),
127 (0x0074, (Some("set_cursor"), &[])),
128 (0x0075, (Some("set_hide_cursor_time"), &[])),
129 (0x0076, (Some("get_hide_cursor_time"), &[])),
130 (0x0077, (Some("scene_skip"), &[])),
131 (0x0078, (Some("cancel_scene_skip"), &[])),
132 (0x0079, (Some("lsize"), &[])),
133 (0x007A, (Some("get_async_key"), &[])),
134 (0x007B, (Some("get_font_color"), &[])),
135 (0x007C, (Some("get_current_date"), &[])),
136 (0x007D, (Some("history_skip"), &[])),
137 (0x007E, (Some("cancel_history_skip"), &[])),
138 (0x007F, (None, &[])),
139 (0x0081, (Some("system_btn_set"), &[])),
140 (0x0082, (Some("system_btn_release"), &[])),
141 (0x0083, (Some("system_btn_enable"), &[])),
142 (0x0086, (Some("text_init"), &[])),
143 (0x0087, (Some("text_set_icon"), &[])),
144 (0x0088, (Some("text"), &[])),
145 (0x0089, (Some("text_hide"), &[])),
146 (0x008A, (Some("text_show"), &[])),
147 (0x008B, (Some("text_set_btn"), &[])),
148 (0x008C, (Some("text_uninit"), &[])),
149 (0x008D, (Some("text_set_rect"), &[])),
150 (0x008E, (Some("text_clear"), &[])),
151 (0x008F, (None, &[])),
152 (0x0090, (Some("text_get_time"), &[])),
153 (0x0091, (Some("text_window_set_alpha"), &[])),
154 (0x0092, (Some("text_voice_play"), &[])),
155 (0x0093, (None, &[])),
156 (0x0094, (Some("text_set_icon_animation_time"), &[])),
157 (0x0095, (Some("text_w"), &[])),
158 (0x0096, (Some("text_a"), &[])),
159 (0x0097, (Some("text_wa"), &[])),
160 (0x0098, (Some("text_n"), &[])),
161 (0x0099, (Some("text_cat"), &[])),
162 (0x009A, (Some("set_history"), &[])),
163 (0x009B, (Some("is_text_visible"), &[])),
164 (0x009C, (Some("text_set_base"), &[])),
165 (0x009D, (Some("enable_voice_cut"), &[])),
166 (0x009E, (Some("is_voice_cut"), &[])),
167 (0x009F, (None, &[])),
168 (0x00A0, (None, &[])),
169 (0x00A1, (None, &[])),
170 (0x00A2, (Some("text_set_color"), &[])),
171 (0x00A3, (Some("text_redraw"), &[])),
172 (0x00A4, (Some("set_text_mode"), &[])),
173 (0x00A5, (Some("text_init_visualnovelmode"), &[])),
174 (0x00A6, (Some("text_set_icon_mode"), &[])),
175 (0x00A7, (Some("text_vn_br"), &[])),
176 (0x00A8, (None, &[])),
177 (0x00A9, (None, &[])),
178 (0x00AA, (None, &[])),
179 (0x00AB, (None, &[])),
180 (0x00AC, (Some("tips_get_str"), &[])),
181 (0x00AD, (Some("tips_get_param"), &[])),
182 (0x00AE, (Some("tips_reset"), &[])),
183 (0x00AF, (Some("tips_search"), &[])),
184 (0x00B0, (Some("tips_set_color"), &[])),
185 (0x00B1, (Some("tips_stop"), &[])),
186 (0x00B2, (Some("tips_get_flag"), &[])),
187 (0x00B3, (Some("tips_init"), &[])),
188 (0x00B4, (Some("tips_pause"), &[])),
189 (0x00B6, (Some("voice_play"), &[])),
190 (0x00B7, (Some("voice_stop"), &[])),
191 (0x00B8, (Some("voice_set_volume"), &[])),
192 (0x00B9, (Some("voice_get_volume"), &[])),
193 (0x00BA, (Some("set_voice_info"), &[])),
194 (0x00BB, (Some("voice_enable"), &[])),
195 (0x00BC, (Some("is_voice_enable"), &[])),
196 (0x00BD, (None, &[])),
197 (0x00BE, (Some("bgv_play"), &[])),
198 (0x00BF, (Some("bgv_stop"), &[])),
199 (0x00C0, (Some("bgv_enable"), &[])),
200 (0x00C1, (Some("get_voice_ex_volume"), &[])),
201 (0x00C2, (Some("set_voice_ex_volume"), &[])),
202 (0x00C3, (Some("voice_check_enable"), &[])),
203 (0x00C4, (Some("voice_autopan_initialize"), &[])),
204 (0x00C5, (Some("voice_autopan_enable"), &[])),
205 (0x00C6, (Some("set_voice_autopan"), &[])),
206 (0x00C7, (Some("is_voice_autopan_enable"), &[])),
207 (0x00C8, (Some("voice_wait"), &[])),
208 (0x00C9, (Some("bgv_pause"), &[])),
209 (0x00CA, (Some("bgv_mute"), &[])),
210 (0x00CB, (Some("set_bgv_volume"), &[])),
211 (0x00CC, (Some("get_bgv_volume"), &[])),
212 (0x00CD, (Some("set_bgv_auto_volume"), &[])),
213 (0x00CE, (Some("voice_mute"), &[])),
214 (0x00CF, (Some("voice_call"), &[])),
215 (0x00D0, (Some("voice_call_clear"), &[])),
216 (0x00D2, (Some("wait"), &[])),
217 (0x00D3, (Some("wait_click"), &[])),
218 (0x00D4, (Some("wait_sync_begin"), &[])),
219 (0x00D5, (Some("wait_sync"), &[])),
220 (0x00D6, (Some("wait_sync_end"), &[])),
221 (0x00D7, (None, &[])),
222 (0x00D8, (Some("wait_clear"), &[])),
223 (0x00D9, (Some("wait_click_no_anim"), &[])),
224 (0x00DA, (Some("wait_sync_get_time"), &[])),
225 (0x00DB, (Some("wait_time_push"), &[])),
226 (0x00DC, (Some("wait_time_pop"), &[])),
227];
228const MOV: u16 = 0x0001;
229const CALL: u16 = 0x000B;
230const SYSCALL: u16 = 0x0017;
231const RET: u16 = 0x0018;
232const PUSH: u16 = 0x001F;
233const ENTER: u16 = 0x0020;
234const SELECT_ADD_CHOICE: u16 = 0x003A;
235const TEXT: u16 = 0x0088;
236const TEXT_W: u16 = 0x0095;
237const TEXT_A: u16 = 0x0096;
238const TEXT_WA: u16 = 0x0097;
239const TEXT_N: u16 = 0x0098;
240const TEXT_CAT: u16 = 0x0099;
241pub const CODE_OFFSET: u32 = 0xC;
242const BIN_XOR: u16 = 0x0008;
243
244#[derive(Clone, Copy, Debug)]
245struct Operand {
246 offset: u32,
247 raw_value: u32,
248}
249
250#[derive(Debug, Clone, Copy, PartialEq, Eq, IntEnum)]
251#[repr(u32)]
252enum OperandType {
253 Literal = 0,
254 Variable = 4,
255 Argument = 8,
256 UNK = 0xFF,
257}
258
259impl Operand {
260 pub fn typ(&self) -> OperandType {
261 let typ = (self.raw_value >> 28) & 0xF;
262 OperandType::try_from(typ).unwrap_or(OperandType::UNK)
263 }
264
265 pub fn raw_type(&self) -> u32 {
266 (self.raw_value >> 28) & 0xF
267 }
268
269 pub fn value(&self) -> u32 {
270 self.raw_value & 0x0FFFFFFF
271 }
272}
273
274impl std::fmt::Display for Operand {
275 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
276 write!(f, "0x{:08X}", self.raw_value)
277 }
278}
279
280struct Instruction {
281 offset: u32,
282 opcode: u16,
283 operands: Vec<Operand>,
284}
285
286impl Instruction {
287 pub fn is_message(&self) -> bool {
288 match self.opcode {
289 TEXT | TEXT_W | TEXT_A | TEXT_WA | TEXT_N | TEXT_CAT => true,
290 SYSCALL => {
291 if self.operands.is_empty() {
292 false
293 } else {
294 let raw_value = self.operands[0].raw_value;
295 match raw_value {
296 0x20002 | 0x2000F | 0x20010 | 0x20011 | 0x20012 | 0x20013 => true,
297 _ => false,
298 }
299 }
300 }
301 _ => false,
302 }
303 }
304}
305
306struct UserMessageFunction {
307 num_args: u32,
308 name_arg_index: u32,
309 message_arg_index: u32,
310}
311
312struct UserChoiceFunction {
313 num_args: u32,
314 choice_arg_indexs: Vec<u32>,
315}
316
317pub struct Disasm<'a> {
318 reader: MemReaderRef<'a>,
319 label_offsets: Vec<u32>,
320 user_message_functions: HashMap<u32, UserMessageFunction>,
321 user_choice_functions: HashMap<u32, UserChoiceFunction>,
322 variables: HashMap<u32, Operand>,
323 stack: Vec<Operand>,
324 strs: Vec<PalString>,
325 pre_is_hover_text_move: bool,
326 pre_is_hover_text_push: bool,
327 pre_is_hover_text_binxor: bool,
328 hover_text: Option<u32>,
329}
330
331#[derive(Debug)]
332pub enum StringType {
333 Name,
334 Message,
335 Hover,
337 Label,
339}
340
341impl StringType {
342 pub fn is_label(&self) -> bool {
343 matches!(self, StringType::Label)
344 }
345}
346
347#[derive(Debug)]
348pub struct PalString {
349 pub offset: u32,
350 pub typ: StringType,
351}
352
353impl<'a> Disasm<'a> {
354 pub fn new(data: &'a [u8], label_offsets: &[u32]) -> Result<Self> {
355 let mut reader = MemReaderRef::new(data);
356 let mut magic = [0; 4];
357 reader.read_exact(&mut magic)?;
358 if magic != *b"Sv20" {
359 return Err(anyhow::anyhow!(
360 "Invalid magic number for Softpal script: {:?}",
361 magic
362 ));
363 }
364 Ok(Self {
365 reader,
366 label_offsets: label_offsets.to_vec(),
367 user_message_functions: HashMap::new(),
368 user_choice_functions: HashMap::new(),
369 variables: HashMap::new(),
370 stack: Vec::new(),
371 strs: Vec::new(),
372 pre_is_hover_text_move: false,
373 hover_text: None,
374 pre_is_hover_text_push: false,
375 pre_is_hover_text_binxor: false,
376 })
377 }
378
379 pub fn disassemble<W: Write + ?Sized>(
380 mut self,
381 mut writer: Option<&mut W>,
382 ) -> Result<Vec<PalString>> {
383 self.find_user_functions()?;
384 self.reader.pos = CODE_OFFSET as usize;
385 let len = self.reader.data.len();
386 while self.reader.pos < len {
387 let instr = self.read_instruction()?;
388 if let Some(writer) = writer.as_mut() {
389 self.write_instruction_to(&instr, writer)?;
390 }
391 let is_hover_text_move = instr.opcode == MOV
392 && instr.operands[0].typ() == OperandType::Variable
393 && instr.operands[0].value() >= 1
394 && instr.operands[1].typ() == OperandType::Literal
395 && instr.operands[1].value() < 0xFFFFFFF;
396 let hover_text = if is_hover_text_move {
397 Some(instr.operands[0].value())
398 } else {
399 None
400 };
401 let mut is_hover_text_push = false;
402 let mut is_hover_text_binxor = false;
403 if instr.is_message() {
404 self.handle_message_instruction()?;
405 } else if instr.opcode == MOV {
406 self.handle_mov_instruction(instr)?;
407 } else if instr.opcode == PUSH {
408 is_hover_text_push = self.handle_push_instruction(instr)?;
409 } else if instr.opcode == CALL {
410 self.handle_call_instruction(instr)?;
411 } else if instr.opcode == SYSCALL {
412 self.handle_syscall_instruction(instr)?;
413 } else if instr.opcode == SELECT_ADD_CHOICE {
414 self.handle_select_choice_instruction()?;
415 } else if instr.opcode == BIN_XOR {
416 if let Some(var) = self.hover_text {
417 if instr.operands[0].typ() == OperandType::Variable
418 && instr.operands[0].value() == var - 1
419 && instr.operands[1].typ() == OperandType::Variable
420 && instr.operands[1].value() == var - 1
421 {
422 is_hover_text_binxor = true;
423 } else {
424 self.hover_text = None;
425 }
426 } else {
427 self.stack.clear();
428 }
430 } else {
431 self.stack.clear();
433 }
435 self.pre_is_hover_text_move = is_hover_text_move;
436 self.pre_is_hover_text_push = is_hover_text_push;
437 self.pre_is_hover_text_binxor = is_hover_text_binxor;
438 if is_hover_text_move {
439 self.hover_text = hover_text;
440 }
441 }
442 Ok(self.strs)
443 }
444
445 fn read_instruction(&mut self) -> Result<Instruction> {
446 let offset = self.reader.pos as u32;
447 let opcode = self.reader.read_u32()?;
448 if (opcode >> 16) != 1 {
449 return Err(anyhow::anyhow!(
450 "Invalid opcode format: 0x{:08X} at offset 0x{:08X}",
451 opcode,
452 offset
453 ));
454 }
455 let opcode = (opcode & 0xFFFF) as u16;
456 let (_, (_, opers)) = OPS.iter().find(|(op, _)| *op == opcode).ok_or_else(|| {
457 anyhow::anyhow!(
458 "Unknown opcode: 0x{:04X} at offset 0x{:08X}",
459 opcode,
460 offset
461 )
462 })?;
463 let mut operands = Vec::new();
464 for _ in *opers {
465 let offset = self.reader.pos as u32;
466 let raw_value = self.reader.read_u32()?;
467 operands.push(Operand { offset, raw_value });
468 }
469 Ok(Instruction {
470 offset,
471 opcode,
472 operands,
473 })
474 }
475
476 fn write_instruction_to(&self, instr: &Instruction, writer: &mut dyn Write) -> Result<()> {
477 let (_, (name, opers)) =
478 OPS.iter()
479 .find(|(op, _)| *op == instr.opcode)
480 .ok_or_else(|| {
481 anyhow::anyhow!(
482 "Unknown opcode: 0x{:04X} at offset 0x{:08X}",
483 instr.opcode,
484 instr.offset
485 )
486 })?;
487 if let Some(name) = name {
488 write!(writer, "0x{:08X} {}", instr.offset, name)?;
489 } else {
490 write!(writer, "0x{:08X} 0x{:04X}", instr.offset, instr.opcode)?;
491 }
492 for i in 0..instr.operands.len() {
493 writer.write_all(if i == 0 { b" " } else { b", " })?;
494 let value = instr.operands[i].value();
495 let mut typ = opers[i];
496 if typ == L {
497 if instr.operands[i].typ() == OperandType::Literal {
498 write!(writer, "#0x{:08X}", self.label_offsets[value as usize - 1])?;
499 } else {
500 typ = P;
501 }
502 }
503 if typ == P {
504 match instr.operands[i].typ() {
505 OperandType::Literal => write!(writer, "0x{:08X}", value)?,
506 OperandType::Variable => write!(writer, "var_{}", value)?,
507 OperandType::Argument => write!(writer, "arg_{}", value)?,
508 OperandType::UNK => {
509 write!(writer, "{}:[0x{:08X}]", instr.operands[i].raw_type(), value)?
510 }
511 }
512 } else if typ == I {
513 write!(writer, "0x{:08X}", value)?;
514 }
515 }
516 writeln!(writer)?;
517 if instr.opcode == RET {
518 writeln!(writer)?;
519 }
520 Ok(())
521 }
522
523 fn find_user_functions(&mut self) -> Result<()> {
524 let mut current_func_args = None;
525 self.reader.pos = CODE_OFFSET as usize;
526 let mut choice_indexes = Vec::new();
527 let len = self.reader.data.len();
528 while self.reader.pos < len {
529 let instr = self.read_instruction()?;
530 if instr.is_message() {
531 if let Some((func_offset, func_num_args)) = current_func_args {
532 if self.stack.len() >= 4 {
533 let _number = self.stack.pop().unwrap();
534 let name = self.stack.pop().unwrap();
535 let message = self.stack.pop().unwrap();
536 if name.typ() == OperandType::Argument
537 && message.typ() == OperandType::Argument
538 {
539 self.user_message_functions.insert(
540 func_offset,
541 UserMessageFunction {
542 num_args: func_num_args,
543 name_arg_index: name.value() - 1,
544 message_arg_index: message.value() - 1,
545 },
546 );
547 current_func_args = None;
548 }
549 }
550 }
551 self.stack.clear();
552 continue;
554 } else if instr.opcode == SYSCALL && instr.operands[0].raw_value == 0x60002 {
555 let choice = self
556 .stack
557 .pop()
558 .ok_or_else(|| anyhow::anyhow!("No choice for choice sys call"))?;
559 if choice.typ() == OperandType::Argument {
560 choice_indexes.push(choice.value() - 1);
561 }
562 self.stack.clear();
563 if !choice_indexes.is_empty() {
564 if let Some((func_offset, func_num_args)) = current_func_args {
565 self.user_choice_functions.insert(
566 func_offset,
567 UserChoiceFunction {
568 num_args: func_num_args,
569 choice_arg_indexs: choice_indexes.clone(),
570 },
571 );
572 }
573 }
574 continue;
575 }
576 match instr.opcode {
577 ENTER => {
578 current_func_args = Some((instr.offset, instr.operands[0].value()));
579 self.stack.clear();
580 self.variables.clear(); choice_indexes.clear();
582 }
583 MOV => {
584 self.handle_mov_instruction(instr)?;
585 }
586 PUSH => {
587 self.handle_push_instruction(instr)?;
588 }
589 RET => {
590 current_func_args = None;
591 self.stack.clear();
592 self.variables.clear(); choice_indexes.clear();
594 }
595 _ => {
596 self.stack.clear();
597 }
599 }
600 }
601 Ok(())
602 }
603
604 fn handle_mov_instruction(&mut self, instr: Instruction) -> Result<()> {
605 if instr.operands[0].typ() == OperandType::Variable {
606 let mut rhs = instr.operands[1].clone();
607 if rhs.typ() == OperandType::Variable {
608 self.variables.get(&rhs.value()).map(|resolved| {
609 rhs = resolved.clone();
610 });
611 }
612 self.variables.insert(instr.operands[0].value(), rhs);
613 }
614 Ok(())
615 }
616
617 fn handle_push_instruction(&mut self, instr: Instruction) -> Result<bool> {
618 let mut is_hover_text_push = false;
619 if instr.operands[0].typ() == OperandType::Variable
620 && self.variables.contains_key(&instr.operands[0].value())
621 {
622 let var = self.variables.get(&instr.operands[0].value()).unwrap();
623 if self.pre_is_hover_text_move {
624 if let Some(hover_text) = self.hover_text {
625 if instr.operands[0].value() == hover_text {
626 is_hover_text_push = true;
627 } else {
628 self.hover_text = None;
629 }
630 }
631 }
632 self.stack.push(*var);
633 } else {
634 if self.pre_is_hover_text_binxor
635 && instr.operands[0].raw_type() == 5
636 && instr.operands[0].value() & 0x10000 != 0
637 {
638 if let Some(hover_text) = self.hover_text {
639 if let Some(var) = self.variables.get(&hover_text) {
640 if var.typ() == OperandType::Literal && var.value() < 0xFFFFFFF {
641 self.strs.push(PalString {
642 offset: var.offset,
643 typ: StringType::Hover,
644 });
645 }
646 }
647 self.hover_text = None;
648 }
649 } else {
650 self.hover_text = None;
651 }
652 self.stack.push(instr.operands[0]);
653 }
654 Ok(is_hover_text_push)
655 }
656
657 fn handle_call_instruction(&mut self, instr: Instruction) -> Result<()> {
658 let err = self.handle_call_instruction_internal(instr);
659 self.stack.clear();
660 err
662 }
663
664 fn handle_call_instruction_internal(&mut self, instr: Instruction) -> Result<()> {
665 if self.label_offsets.is_empty() || instr.operands[0].typ() != OperandType::Literal {
666 return Ok(());
667 }
668 let target_offset = self.label_offsets[instr.operands[0].value() as usize - 1];
669 if let Some(func) = self.user_choice_functions.get(&target_offset) {
670 if self.stack.len() < func.num_args as usize {
671 return Ok(());
672 }
673 let mut args = Vec::new();
674 for _ in 0..func.num_args {
675 args.push(self.stack.pop().unwrap());
676 }
677 args.reverse();
678 for ind in &func.choice_arg_indexs {
679 let arg = &args[*ind as usize];
680 if arg.typ() == OperandType::Literal {
681 self.strs.push(PalString {
682 offset: arg.offset,
683 typ: StringType::Message,
684 });
685 }
686 }
687 return Ok(());
688 }
689 let message_func = match self.user_message_functions.get(&target_offset) {
690 Some(func) => func,
691 None => return Ok(()),
692 };
693 if self.stack.len() < message_func.num_args as usize {
694 return Ok(());
695 }
696 let mut args = Vec::new();
697 for _ in 0..message_func.num_args {
698 args.push(self.stack.pop().unwrap());
699 }
700 args.reverse();
701 let name = args[message_func.name_arg_index as usize];
702 let message = args[message_func.message_arg_index as usize];
703 if name.typ() == OperandType::Literal && message.typ() == OperandType::Literal {
704 self.strs.push(PalString {
705 offset: name.offset,
706 typ: StringType::Name,
707 });
708 self.strs.push(PalString {
709 offset: message.offset,
710 typ: StringType::Message,
711 });
712 }
713 Ok(())
714 }
715
716 fn handle_syscall_instruction(&mut self, instr: Instruction) -> Result<()> {
717 match instr.operands[0].raw_value {
718 0x60002 => {
719 self.handle_select_choice_instruction()?;
720 }
721 0x20014 => {
722 self.handle_another_message()?;
723 }
724 0xf0002 => {
725 self.handle_label()?;
726 }
727 _ => {
728 self.stack.clear();
729 }
730 }
731 Ok(())
732 }
733
734 fn handle_message_instruction(&mut self) -> Result<()> {
735 let err = self.handle_message_instruction_internal();
736 self.stack.clear();
737 err
739 }
740
741 fn handle_another_message(&mut self) -> Result<()> {
742 if self.stack.len() < 3 {
743 return Ok(());
744 }
745 let _message_id = self.stack.pop().unwrap();
746 let name = self.stack.pop().unwrap();
747 let message = self.stack.pop().unwrap();
748 if name.typ() != OperandType::Literal || message.typ() != OperandType::Literal {
749 return Ok(());
750 }
751 self.strs.push(PalString {
752 offset: name.offset,
753 typ: StringType::Name,
754 });
755 self.strs.push(PalString {
756 offset: message.offset,
757 typ: StringType::Message,
758 });
759 Ok(())
760 }
761
762 fn handle_label(&mut self) -> Result<()> {
763 if self.stack.len() < 1 {
764 return Ok(());
765 }
766 let label = self.stack.pop().unwrap();
767 if label.typ() != OperandType::Literal {
768 return Ok(());
769 }
770 self.strs.push(PalString {
771 offset: label.offset,
772 typ: StringType::Label,
773 });
774 Ok(())
775 }
776
777 fn handle_message_instruction_internal(&mut self) -> Result<()> {
778 if self.stack.len() < 4 {
779 return Ok(());
780 }
781 let _number = self.stack.pop().unwrap();
782 let name = self.stack.pop().unwrap();
783 let message = self.stack.pop().unwrap();
784 if name.typ() != OperandType::Literal || message.typ() != OperandType::Literal {
785 return Ok(());
786 }
787 self.strs.push(PalString {
788 offset: name.offset,
789 typ: StringType::Name,
790 });
791 self.strs.push(PalString {
792 offset: message.offset,
793 typ: StringType::Message,
794 });
795 Ok(())
796 }
797
798 fn handle_select_choice_instruction(&mut self) -> Result<()> {
799 let err = self.handle_select_choice_instruction_internal();
800 self.stack.clear();
801 err
803 }
804
805 fn handle_select_choice_instruction_internal(&mut self) -> Result<()> {
806 if self.stack.len() < 1 {
807 return Ok(());
808 }
809 let choice = self.stack.pop().unwrap();
810 self.strs.push(PalString {
811 offset: choice.offset,
812 typ: StringType::Message,
813 });
814 Ok(())
815 }
816}